﻿// ===============================================================================
// PageContext.cs
// EOS Web Framework
// ===============================================================================
// Copyright (c) EOS Development Group. All rights reserved.
// ===============================================================================

namespace EOS.Framework.Web.Mvc
{
    using System;
    using System.Globalization;
    using System.Web;
    using EOS.Framework.Tools.Aspects;

    /// <summary>
    /// Contains all context values for a single web page.
    /// </summary>
    public abstract class PageContext
    {
        #region Properties        
        
        private ParameterDictionary _parameters;

        /// <summary>
        /// Returns a list of parameters.
        /// </summary>
        /// <value>The parameters.</value>
        public ParameterDictionary Parameters
        {
            get { return _parameters; }
        }

        private HttpContext _httpContext;

        /// <summary>
        /// Gets the HTTP context.
        /// </summary>
        /// <value>The HTTP context.</value>
        public HttpContext HttpContext
        {
            get { return _httpContext; }
        } 
        
        private string _applicationPath = string.Empty;

        /// <summary>
        /// Gets the application path.
        /// </summary>
        /// <value>The application path.</value>
        public string ApplicationPath
        {
            get { return _applicationPath; }
        }

        private string _action = string.Empty;

        /// <summary>
        /// Gets the action.
        /// </summary>
        /// <value>The action.</value>
        public string Action
        {
            get { return _action; }
        }

        private string _webPage = string.Empty;

        /// <summary>
        /// Gets the page.
        /// </summary>
        /// <value>The page.</value>
        public string WebPage
        {
            get { return _webPage; }
        }

        private string _url = string.Empty;

        /// <summary>
        /// Gets the URL.
        /// </summary>
        /// <value>The URL.</value>
        public string Url
        {
            get { return _url; }
        }

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="PageContext"/> class.
        /// </summary>
        /// <param name="httpContext">The HTTP context. Cannot be null (Nothing in Visual Basic).</param>
        /// <param name="url">The URL. Cannot be null (Nothing in Visual Basic) or empty and cannot contain only blanks.</param>
        /// <param name="applicationPath">The application path. Cannot be null (Nothing in Visual Basic) or empty
        /// and cannot contain only blanks.</param>
        /// <param name="page">The name of the page. Cannot be null (Nothing in Visual Basic) or
        /// empty and cannot contain only blanks.</param>
        /// <param name="action">The action. Cannot be null (Nothing in Visual Basic) or empty
        /// and cannot contain only blanks.</param>
        /// <param name="parameters">A collection of parameters. Cannot be null (Nothing in Visual Basic).</param>
        /// <exception cref="ArgumentNullException">
        /// 	<para><paramref name="httpContext"/> is null (Nothing in Visual Basic).</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="url"/> is null (Nothing in Visual Basic).</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="applicationPath"/> is null (Nothing in Visual Basic).</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="page"/> is null (Nothing in Visual Basic).</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="action"/> is null (Nothing in Visual Basic).</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="applicationPath"/> is null (Nothing in Visual Basic).</para>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// 	<para><paramref name="url"/> is a string of length 0 or contains only blanks.</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="applicationPath"/> is a string of length 0 or contains only blanks.</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="page"/> is a string of length 0 or contains only blanks.</para>
        /// 	<para>- or -</para>
        /// 	<para><paramref name="action"/> is a string of length 0 or contains only blanks.</para>
        /// </exception>
        protected PageContext(HttpContext httpContext, string url, string applicationPath, 
            string page, string action, ParameterDictionary parameters)
        {            
            this._applicationPath = applicationPath;
            this._webPage = page;
            this._action = action;
            this._url = url; 
            this._parameters = parameters;

            this._httpContext = httpContext; 
        }

        /// <summary>
        /// Gets the parameter by a specified key.
        /// </summary>
        /// <param name="key">The key of the parameter.</param>
        /// <returns>The parameter.</returns>
        /// <exception cref="ArgumentException">A parameter for the specified
        /// <paramref name="key"/> does not exist.</exception>
        public object GetParameter(string key)
        {
            if (_parameters.ContainsKey(key) == false)
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                    Properties.Resources.ParameterNotExists, key));
            }

            return _parameters[key];
        }

        /// <summary>
        /// Gets the parameter by a specified key..
        /// </summary>
        /// <typeparam name="TValue">The target type of the value.</typeparam>
        /// <param name="key">The key of the parameter.</param>
        /// <returns>The converted parameter.</returns>
        /// <exception cref="ArgumentException">A parameter for the specified
        /// <paramref name="key"/> does not exist.</exception>
        /// <exception cref="InvalidCastException">A cast to the specified type
        /// is not possbible.</exception>
        public TValue GetParameter<TValue>(string key)
        {
            object source = GetParameter(key);

            Type targetType = typeof(TValue);
            Type sourceType = source.GetType();

            if (sourceType.Equals(targetType) ||
                sourceType.IsSubclassOf(targetType) ||
                sourceType.IsInstanceOfType(targetType) ||
                targetType.IsAssignableFrom(source.GetType()))
            {
                return (TValue)source;
            }
            else if (source is IConvertible)
            {
                try
                {
                    return (TValue)Convert.ChangeType(source, targetType);
                }
                catch (InvalidCastException e)
                {
                    throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture,
                        Properties.Resources.WrongParameterType, typeof(TValue).Name), e);
                }
            }
            else
            {
                throw new InvalidCastException(string.Format(CultureInfo.CurrentCulture,
                    Properties.Resources.WrongParameterType, typeof(TValue).Name));
            }
        }

        /// <summary>
        /// Refreshs the page by making a redirect to the current url.
        /// </summary>
        /// <exception cref="HttpException">A redirection is attempted after
        /// the HTTP headers have been sent.</exception>
        /// <exception cref="ApplicationException">The page request is the
        /// result of a callback.</exception>
        public void Refresh()
        {
            HttpContext.Response.Redirect(Url);
        }

        /// <summary>
        /// Redirects a client to a new URL and specifies the new URL.
        /// </summary>
        /// <param name="url">The target location. Cannot be null or empty or contains
        /// only blanks.</param>
        /// <exception cref="HttpException">A redirection is attempted after 
        /// the HTTP headers have been sent.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="url"/> is 
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref name="url"/> is 
        /// a string of length 0 or contains only blanks.</exception>
        [ParamNotNullOrEmpty("url")]
        public void Redirect(string url)
        {
            HttpContext.Response.Redirect(url);
        }

        /// <summary>
        /// Redirects a client to a new URL. Specifies the new URL and whether execution
        /// of the current page should terminate.
        /// </summary>
        /// <param name="url">The target location. Cannot be null or empty or contains
        /// only blanks.</param>
        /// <param name="endResponse">Indicates whether execution of the current page should terminate.</param>
        /// <exception cref="HttpException">A redirection is attempted after
        /// the HTTP headers have been sent.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="url"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref name="url"/> is
        /// a string of length 0 or contains only blanks.</exception>
        /// <exception cref="ApplicationException">The page request is the
        /// result of a callback.</exception>
        [ParamNotNullOrEmpty("url")]
        public void Redirect(string url, bool endResponse)
        {
            HttpContext.Response.Redirect(url, endResponse);
        }
    }
}
